/*
事件派发器的封装实现 -- 将不同的请求/应答派发到不同的回调函数
*/

#pragma once

#include <unordered_map>
#include <mutex>
#include <memory>

#include "Message.hpp"

namespace RpcModule
{
    class CallBack
    {
    public:
        using ptr = std::shared_ptr<CallBack>;
        virtual void OnMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &message) = 0;
    };

    // 在设置消息类型时，可以使用：
    template <typename T>
    class CallBackT : public CallBack
    {
    public:
        using ptr = std::shared_ptr<CallBackT>;
        using MessageCallBack = std::function<void(const BaseConnection::ptr &conn, std::shared_ptr<T> &message)>;
        CallBackT(const MessageCallBack &handler) : _handler(handler) {}

        void OnMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &message) override
        {
            // 如果是Rpc请求消息，就将BaseMessage转化为RpcRequest消息即可
            auto type_message = std::dynamic_pointer_cast<T>(message);
            _handler(conn, type_message);
        }

    private:
        MessageCallBack _handler;
    };

    class Dispatcher
    {
    public:
        using ptr = std::shared_ptr<Dispatcher>;

        template <typename T>
        // 将消息类型与消息对应的回调函数注册到unordered_map中
        // 我们想的效果为：传入RpcRequest，直接构造出RpcRequest的CallBack派生类，这样在进行回调函数的实现时
        // 知道该回调函数是Rpc调用，就可以直接在函数中访问Rpc请求提供的接口了
        // void OnRpcRequest(const RpcModule::BaseConnection::ptr &conn, RpcModule::RpcRequest::ptr &message)
        // dispatcher->RegisterHandler<RpcModule::RpcRequest>(RpcModule::MType::REQ_RPC, OnRpcRequest);
        void RegisterHandler(MType mtype, const typename CallBackT<T>::MessageCallBack &handler)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto callback = std::make_shared<CallBackT<T>>(handler);
            _handlers.insert(std::make_pair(mtype, callback));
        }
        void OnMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &message)
        {
            // 1. 消息到来，只需要找到对应的回调函数，进行处理即可
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _handlers.find(message->GetMtype());
            if (it == _handlers.end())
            {
                LOGERROR("函数处理前异常：没有与之对应的处理函数，连接关闭, %d", (int)message->GetMtype());
                conn->ShutDown();
                return;
            }
            // 2. 这里使用callback中的onmessage调用
            it->second->OnMessage(conn, message);
        }

    private:
        std::mutex _mutex;
        std::unordered_map<MType, CallBack::ptr> _handlers;
    };
}